package com.benio.ycfdisplayer.fresco.photoview;

import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;

import com.benio.ycfdisplayer.displayer.DisplayListener;
import com.benio.ycfdisplayer.displayer.Options;
import com.benio.ycfdisplayer.displayer.Target;
import com.benio.ycfdisplayer.fresco.FrescoDisplayOptions;
import com.benio.ycfdisplayer.fresco.FrescoExecutor;
import com.benio.ycfdisplayer.fresco.FrescoOptionsApplier;
import com.facebook.drawee.controller.AbstractDraweeController;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.drawable.FadeDrawable;
import com.facebook.drawee.generic.RootDrawable;
import com.facebook.imagepipeline.image.ImageInfo;

import uk.co.senab.photoview.PhotoView;

/**
 * An Executor that loads image into {@link com.benio.ycfdisplayer.fresco.FrescoViewTarget}
 * and {@link PhotoViewTarget}.
 * Created by zhangzhibin on 2016/10/9.
 */
public class PhotoViewExecutor extends FrescoExecutor {

    public PhotoViewExecutor() {
    }

    @Override
    protected void execute(String uriString, Target target, Options options, DisplayListener listener) {
        // 判断如果是PhotoViewTarget的话则处理掉，否则转交父类处理
        if (target instanceof PhotoViewTarget) {
            PhotoViewTarget photoViewTarget = (PhotoViewTarget) target;
            AbstractDraweeController newController = FrescoOptionsApplier.newControllerBuilder(uriString, photoViewTarget, options, listener).build();
            if (!TextUtils.isEmpty(uriString)) {
                ControllerListener controllerListener = new MyControllerListenerWrapper(photoViewTarget, options);
                newController.addControllerListener(controllerListener);
            }
            photoViewTarget.setController(newController);
        } else {
            super.execute(uriString, target, options, listener);
        }
    }

    /**
     * 以下为关键代码，PhotoView和Fresco结合使用必须加上
     */
    private static class MyControllerListenerWrapper extends BaseControllerListener<ImageInfo> {
        private PhotoViewTarget mTarget;
        private boolean mTapToRetryEnabled;

        public MyControllerListenerWrapper(PhotoViewTarget target, Options options) {
            mTarget = target;
            // 获取当前Options中是否开启retry
            mTapToRetryEnabled = options instanceof FrescoDisplayOptions && ((FrescoDisplayOptions) options).tapToRetryEnabled;
        }

        @Override
        public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
            if (imageInfo == null) {
                return;
            }

            final int width = imageInfo.getWidth();
            final int height = imageInfo.getHeight();
            final WrapperDrawable wrapperDrawable = new WrapperDrawable(mTarget.getHierarchy().getTopLevelDrawable());
            wrapperDrawable.setIntrinsicWidth(width);
            wrapperDrawable.setIntrinsicHeight(height);
            mTarget.setDrawable(wrapperDrawable);
            clearFadeEffect(wrapperDrawable);

            // 使用retryImage的时候，需要在失败的时候需调用PhotoView的setZoomable(false)
            // 否则photoView会将touch事件消费掉
            // 只有在加载成功的时候PhotoView才可进行放缩
            setPhotoViewZoomable(true);
        }

        @Override
        public void onFailure(String id, Throwable throwable) {
            setPhotoViewZoomable(false);
        }

        private void setPhotoViewZoomable(boolean zoomable) {
            if (mTapToRetryEnabled) {
                PhotoView photoView = mTarget.getView();
                if (photoView != null) {
                    photoView.setZoomable(zoomable);
                }
            }
        }

        /**
         * 清除所有渐变效果
         */
        private static void clearFadeEffect(Drawable wrapperDrawable) {
            Drawable drawable = wrapperDrawable.getCurrent();
            if (drawable instanceof RootDrawable) {
                drawable = ((RootDrawable) drawable).getCurrent();
                if (drawable instanceof FadeDrawable) {
                    ((FadeDrawable) drawable).finishTransitionImmediately();
                }
            }
        }
    }
}
